/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit.handlers;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.uml2.uml.Continuation;
import org.eclipse.uml2.uml.InteractionOperand;

import com.cea.papyrus.core.utils.LookForElement;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.AnalyseCoveredCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.AnalyseOwnerCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.DecideContinuationBoundsCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.SelectPartCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.CoverCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.CreateContinuationCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.CreateGraphicalElementCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.diagram.SetBoundsHintCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * Handles creation of Continuations.
 * <p>
 * This handler is used from FrameLayoutPolicy.
 * </p>
 * 
 * @author frankd@ifi.uio.no
 */
public class ContinuationCreateHandler implements CreationHandler {

	public final EditPolicy hostPolicy;

	public ContinuationCreateHandler(final EditPolicy hostPolicy) {
		this.hostPolicy = hostPolicy;
	}

	@SuppressWarnings("unchecked")
	public Command[] getCreateCommands(final CreateRequest request) {
		final GraphicalEditPart host = (GraphicalEditPart) hostPolicy.getHost();
		final GraphNode interactionView = (GraphNode) host.getModel();

		// AnalyseOwnerCommand [SeDi]
		// SetBoundsHintCommand [SeDi]
		// Registers a Bounds hint that can be used when the
		// SeDi GraphcialElement is created.
		// CreateContinuationCommand [UML]
		// Creates the UML element and adds it to the UML interaction
		// When the command is executed, a GraphicalElement will be
		// created in response to the notification. This creation will
		// consume the Bounds hint set previously
		// AnalyseCoveredCommand [SeDi]
		// Analyses the diagram and detects any lifelines covering the
		// new fragment. The result is input to the next command:
		// CoverCommand [UML]
		// Sets the fragment's Covered attribute.

		Point location = request.getLocation().getCopy();
		// host.getFigure().translateToAbsolute(location);
		final Diagram diagram = LookForElement.getDiagram(interactionView);
		final AnalyseOwnerCommand analyseOwnerCmd = new AnalyseOwnerCommand();
		analyseOwnerCmd.setAnyEditPart(host);
		analyseOwnerCmd.setDiagram(diagram);
		analyseOwnerCmd.setLocation(location);
		analyseOwnerCmd.execute();
		if (!(analyseOwnerCmd.getOwner() instanceof InteractionOperand))
			return null;

		InteractionOperand owner = (InteractionOperand) analyseOwnerCmd
				.getOwner();

		final DecideContinuationBoundsCommand analyseBoundsCmd = new DecideContinuationBoundsCommand();
		analyseBoundsCmd.setAnyEditPart(host);
		analyseBoundsCmd.setDiagram(diagram);
		analyseBoundsCmd.setHint(new Rectangle(location,
				request.getSize() != null ? request.getSize() : new Dimension(
						0, 0)));
		analyseBoundsCmd.setOperand(owner);

		final SetBoundsHintCommand hintCmd = new SetBoundsHintCommand();
		// glue1: setHint

		final CreateContinuationCommand createCmd = new CreateContinuationCommand();
		createCmd.setOperand(owner);

		final CreateGraphicalElementCommand createGECmd = new CreateGraphicalElementCommand();
		createGECmd.setAnyEditPart(host);
		GraphElement parentGE = ModelUtil.getGraphElement(owner.getOwner(),
				diagram);
		createGECmd.setParentGE(parentGE);

		final AnalyseCoveredCommand analyseCoveredCmd = new AnalyseCoveredCommand();
		analyseCoveredCmd.setEditPart(host);

		final CoverCommand coverCmd = new CoverCommand();

		final SelectPartCommand selectCmd = new SelectPartCommand();
		selectCmd.setAnyEditPart(hostPolicy.getHost().getRoot());
		selectCmd.setSelectForEdit(true);

		final Command glue1 = new Command() {
			public void execute() {
				Rectangle hint = analyseBoundsCmd.getPreferredBounds();
				host.getFigure().translateToRelative(hint);
				host.getFigure().translateFromParent(hint);
				hintCmd.setHint(hint);
			}
		};

		final Command glueGE = new Command() {
			@Override
			public void execute() {
				createGECmd.setElement(createCmd.getContinuation());
			}
		};

		final Command glue2 = new Command() {
			public void execute() {
				Continuation continuation = createCmd.getContinuation();
				GraphNode continuationView = ModelUtil.getGraphNode(
						continuation, diagram);
				analyseCoveredCmd.setFragmentView(continuationView);
			}
		};

		final Command glue3 = new Command() {
			public void execute() {
				coverCmd.setFragment(createCmd.getContinuation());
				coverCmd.setCovered(analyseCoveredCmd.getCovered());
				selectCmd.setTarget(createCmd.getContinuation());
			}
		};

		return new Command[] { analyseBoundsCmd, glue1, hintCmd, createCmd,
				glueGE, createGECmd, glue2, analyseCoveredCmd, glue3, coverCmd,
				selectCmd };
	}
}
